#include "GlDistributor.h"

#include "GlListener.h"

namespace GraphicLibrary
{
	//-----------------------------------------------
	template<typename ListenerType>
		void Distributor<ListenerType>::disconnectAll() const
		{
			for(ListenerArray::iterator i = mListeners.begin(); i != mListeners.end(); ++i)
				i->mListener->disconnectedFrom((const ListenerType::MyDistributor*)this);
				//i->mListener->disconnectedFrom(static_cast<const ListenerType::MyDistributor*>(this));
			mListeners.clear();
		}

	//-----------------------------------------------
	template<typename ListenerType>
		void Distributor<ListenerType>::connect(ListenerType *listener) const
		{
			if(beforeListenerConnected(listener))
			{
				IdListenerPair newElement(listener);
				ListenerArray::iterator i = std::lower_bound(mListeners.begin(), mListeners.end(), newElement, IdListenerPair::Less());
				if(i == mListeners.end() || !i->mListener || *i->mListener != *listener)
				{
					if(i == mListeners.end() || i->mListener)
						mListeners.insert(i, newElement);
					else
						(*i) = newElement;
					listener->connectedTo(reinterpret_cast<const ListenerType::MyDistributor*>(this));
				}
			}
		}

	//-----------------------------------------------
	template<typename ListenerType>
		void Distributor<ListenerType>::disconnect(ListenerType *listener) const
		{
			ListenerArray::iterator i = std::lower_bound(mListeners.begin(), mListeners.end(), listener->getId(), IdListenerPair::Less());
			if(i != mListeners.end() && (*i).mId == listener->getId() && i->mListener)
			{
				i->mListener = 0;
				afterListenerDisconnected(listener);
				listener->disconnectedFrom(reinterpret_cast<const ListenerType::MyDistributor*>(this));
			}
		}

	//-----------------------------------------------
	template<typename ListenerType>
		void Distributor<ListenerType>::optimize() const
		{
			mListeners.erase(std::remove(mListeners.begin(), mListeners.end(), IdListenerPair::NullPointer), mListeners.end());
		}

	//-----------------------------------------------
	template<typename ListenerType>
		Distributor<ListenerType>::~Distributor()
		{
			disconnectAll();
		}

	//-----------------------------------------------
	template<typename ListenerType>
		bool Distributor<ListenerType>::beforeListenerConnected(ListenerType *listener) const
		{
			return true;
		}

	//-----------------------------------------------
	template<typename ListenerType>
		void Distributor<ListenerType>::afterListenerDisconnected(ListenerType *listener) const
		{
		}

	//-----------------------------------------------
	template<typename ListenerType>
		Distributor<ListenerType>::IdListenerPair::IdListenerPair()
		{
		}

	//-----------------------------------------------
	template<typename ListenerType>
		Distributor<ListenerType>::IdListenerPair::IdListenerPair(ListenerType *listener)
			: mId(listener->getId())
			, mListener(listener)
		{
		}

	//-----------------------------------------------
	template<typename ListenerType>
		bool Distributor<ListenerType>::IdListenerPair::operator == (const TagNullPointer)
		{
			return mListener;
		}

	//-----------------------------------------------
	template<typename ListenerType>
		bool Distributor<ListenerType>::IdListenerPair::Less::operator () (const IdListenerPair &left, const IdListenerPair &right) const
		{
			return left.mId < right.mId;
		}

	//-----------------------------------------------
	template<typename ListenerType>
		bool Distributor<ListenerType>::IdListenerPair::Less::operator () (const IdListenerPair &left, const Id::IdType right) const
		{
			return left.mId < right;
		}

	//-----------------------------------------------
	template<typename ListenerType>
		bool Distributor<ListenerType>::IdListenerPair::Less::operator () (const Id::IdType left, const IdListenerPair &right) const
		{
			return left < right.mId;
		}
}
